﻿using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace BlazorAdmin.Extensions
{
    public static class Utils
    {
        public static string GetClientBrowser(string userAgent)
        {
            var regex = @"(Msie|Firefox|Chrome|Opera|Version).*?([\d.]+)";
            var browserVer = Regex.Match(userAgent ?? string.Empty, regex, RegexOptions.IgnoreCase | RegexOptions.Multiline).Value.Replace("/", " ");

            return browserVer;
        }

        public static string GetClientOS(string userAgent)
        {
            userAgent = userAgent ?? string.Empty;
            var osVersion = string.Empty;

            if (userAgent.Contains("NT 10.0"))
                osVersion = "Windows 10";
            else if (userAgent.Contains("NT 6.3"))
                osVersion = "Windows 8.1";
            else if (userAgent.Contains("NT 6.2"))
                osVersion = "Windows 8";
            else if (userAgent.Contains("NT 6.1"))
                osVersion = "Windows 7";
            else if (userAgent.Contains("NT 6.1"))
                osVersion = "Windows 7";
            else if (userAgent.Contains("NT 6.0"))
                osVersion = "Windows Vista/Server 2008";
            else if (userAgent.Contains("NT 5.2"))
            {
                if (userAgent.Contains("64"))
                    osVersion = "Windows XP";
                else
                    osVersion = "Windows Server 2003";
            }
            else if (userAgent.Contains("NT 5.1"))
                osVersion = "Windows XP";
            else if (userAgent.Contains("NT 5"))
                osVersion = "Windows 2000";
            else if (userAgent.Contains("NT 4"))
                osVersion = "Windows NT4";
            else if (userAgent.Contains("Me"))
                osVersion = "Windows Me";
            else if (userAgent.Contains("98"))
                osVersion = "Windows 98";
            else if (userAgent.Contains("95"))
                osVersion = "Windows 95";
            else if (userAgent.Contains("Mac"))
                osVersion = "Mac";
            else if (userAgent.Contains("Unix"))
                osVersion = "UNIX";
            else if (userAgent.Contains("Linux"))
                osVersion = "Linux";
            else if (userAgent.Contains("SunOS"))
                osVersion = "SunOS";

            return osVersion;
        }

        public static string GetMD5(string encryptStr)
        {
            byte[] md5Bytes, dataBytes = Encoding.UTF8.GetBytes(encryptStr ?? string.Empty);
            using (MD5 md5 = MD5.Create())
                md5Bytes = md5.ComputeHash(dataBytes);

            var sb = new StringBuilder();
            foreach (byte item in md5Bytes)
                sb.Append(item.ToString("x2"));

            return sb.ToString().ToUpper();
        }

        /// <summary>
        /// 获取文件的MD5值
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string GetFileMD5(string path)
        {
            //创建一个MD5算法对象
            using (var md5 = MD5.Create())
            {
                using (var stream = new FileStream(path, FileMode.Open))
                {
                    //哈希算法根据文本得到哈希码的字节数组
                    byte[] hash = md5.ComputeHash(stream);

                    //将字节数组装换为字符串
                    return BitConverter.ToString(hash).Replace("-", "");
                }
            }
        }

        public static bool IsChinese(string value)
        {
            if (string.IsNullOrWhiteSpace(value))
                return false;

            for(var i = 0; i < value.Length; i++)
                if ((int)value[i] > 127)
                    return true;

            return false;
        }

        private static readonly Dictionary<Type, Type> ToStringableNumericTypes;

        static Utils()
        {
            ToStringableNumericTypes = new List<Type>
            {
                typeof(byte),
                typeof(sbyte),
                typeof(short),
                typeof(ushort),
                typeof(int),
                typeof(uint),
                typeof(long),
                typeof(ulong)
            }.ToDictionary((Type a) => a, (Type a) => a);
        }


        public static bool IsToStringableNumericType(Type type)
        {
            type = type.GetUnderlyingType();
            return ToStringableNumericTypes.ContainsKey(type);
        }

        public static Type GetUnderlyingType(this Type type)
        {
            return !type.IsNullable(out Type? underlyingType) ? type : underlyingType;
        }

        /// <summary>
        /// 是否允许为空判断
        /// </summary>
        /// <param name="type"></param>
        /// <param name="underlyingType"></param>
        /// <returns></returns>
        public static bool IsNullable(this Type type, [NotNullWhen(true)] out Type? underlyingType)
        {
            underlyingType = Nullable.GetUnderlyingType(type);
            return underlyingType != null;
        }
    }
}
